#include <iostream>
#include <unistd.h>
#include <assert.h>
#include <string>
#include <cstdio>
#include <cstring>
#include <sys/types.h>
#include <sys/wait.h>
using namespace std;




/* 实验一：父进程写入，子进程读出！ */
/**
 * 提问：为什么不定义全局buffer来进行通信呢？
 * 答：因为有写时拷贝的存在！无法进行通信！
*/

int main(){

    // 1. 创建管道
    int pipefd[2] = {0};        // 管道函数的参数：第一个数据标识：读端；第二个数据标识：写端
    int n = pipe(pipefd);       // 创建管道函数，默认以读写方式打开！（两种!）
    assert(n!=-1);              // debug 下 assert 是有效的！release 下是无效的，会被裁掉。
    (void)n;                    
    /**
     *  注意：此处不建议省略：如果管道创建成功，执行到此，
     * 由于后续不会使用该返回值！release 模式下可能会出现该 n 只定义未使用的问题！
    */
#if DEBUG
    cout << pipefd[0] << " " << pipefd[1] << endl;       // 预测：3 4
#endif

    // 2. 创建子进程
    pid_t id = fork();
    assert(id != -1);
    if(id == 0){
        // 子进程
        // 3. 构建单向通信！
        // 3.1 关闭子进程不需要的 fd
        close(pipefd[1]);       // 关闭写

        char buffer[1024];
        while(true){
            ssize_t s = read(pipefd[0], buffer, sizeof(buffer)-1);  // 注意系统调用没有 '\0' 的概念
            if(s>0){
                // 读取成功！
                buffer[s] = 0;       // 手动添加：字符串结尾标识！
                cout << "Child get a message[" << getppid() << "] Father # " << buffer  << endl;
            }
            else if(s == 0) break;
        }


        exit(0);
    }
    // 父进程
    // 关闭进程不需要的 fd
    close(pipefd[0]);
    string message = "我是你的父亲，我在给你发信息！";
    int cnt = 0;
    char send_buffer[1024];
    while(true){
        // 3.2 构建一个变化的信息
        snprintf(send_buffer, sizeof(send_buffer), "%s[%d] : %d", message.c_str(), getpid(), cnt++);
        // 3.3 写入数据
        write(pipefd[1], send_buffer, strlen(send_buffer));

        sleep(1);
    }

    pid_t ret = waitpid(id, nullptr, 0);
    assert(ret>0);
    (void)ret;


    return 0;
}